package com.xmall.order.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xmall.define.base.ResultCode;
import com.xmall.order.define.dict.AfterSaleStatusEnum;
import com.xmall.define.dict.OrderStatusEnum;
import com.xmall.order.define.dict.RefundStatusEnum;
import com.xmall.order.define.dict.RefundTypeEnum;
import com.xmall.define.dto.order.OrderDto;
import com.xmall.order.define.dto.OrderDtoWithCascade;
import com.xmall.order.define.dto.OrderRefundDto;
import com.xmall.exception.XmallException;
import com.xmall.order.define.dto.platform.OrderRefundDtoForAdmin;
import com.xmall.order.define.request.refund.*;
import com.xmall.order.entity.Order;
import com.xmall.order.entity.OrderItem;
import com.xmall.order.entity.OrderRefund;
import com.xmall.order.entity.OrderRefundHistory;
import com.xmall.order.mapper.OrderRefundMapper;
import com.xmall.order.service.*;
import com.xmall.order.service.other.IMsgService;
import com.xmall.order.utils.ConvertUtils;
import com.xmall.utils.XmallUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 订单退款退货 服务实现类
 */
@Slf4j
@Service
public class OrderRefundServiceImpl extends ServiceImpl<OrderRefundMapper, OrderRefund> implements IOrderRefundService {

    @Resource
    private IMsgService msgService;

    @Resource
    private IOrderService orderService;

    @Resource
    private IOrderItemService orderItemService;

    @Resource
    private IOrderRefundRetryLogService orderRefundRetryLogService;

    @Resource
    private IOrderRefundHistoryService orderRefundHistoryService;

    /**
     * 过滤掉拒绝状态的记录
     */
    public List<OrderRefundDto> listWithoutInvalidByOrderId(Long orderId) {
        List<OrderRefund> orderRefundList = this.list(new QueryWrapper<OrderRefund>()
                .eq("order_id", orderId)
                .ne("refund_status", RefundStatusEnum.REFUSE.getStatus())
                .ne("refund_status", RefundStatusEnum.CANCELED.getStatus()));
        return ConvertUtils.OrderRefundModule.INSTANCE.toDtoList(orderRefundList);
    }

    /**
     * 售后列表
     */
    @Override
    public List<OrderRefundDto> listByOrderId(Long orderId) {
        List<OrderRefund> orderRefundList = this.list(new QueryWrapper<OrderRefund>().eq("order_id", orderId));
        return ConvertUtils.OrderRefundModule.INSTANCE.toDtoList(orderRefundList);
    }

    /**
     * 检查是否有退款未处理
     */
    @Override
    public Boolean hasUnhandledRefund(Long orderId) {
        Order order = orderService.getById(orderId);
        XmallUtils.notNull(order);

        Integer orderStatus = order.getOrderStatus();
        List<OrderRefundDto> orderRefundList = this.listWithoutInvalidByOrderId(orderId);

        // 售前
        if (OrderStatusEnum.WAIT_CONSIGN.getStatus() == orderStatus) {
            if(orderRefundList.size() == 1 && RefundStatusEnum.WAIT_AUDIT.getStatus() == orderRefundList.get(0).getRefundStatus()) {
                return true;
            }
        }
        // 售后
        if (OrderStatusEnum.WAIT_RECEIVE.getStatus() == orderStatus
                || OrderStatusEnum.FINISHED.getStatus() == orderStatus
                || OrderStatusEnum.PART_REFUND.getStatus() == orderStatus) {
            return orderRefundList.stream().anyMatch(orderRefund ->
                RefundStatusEnum.WAIT_AUDIT.getStatus() == orderRefund.getRefundStatus() ||
                RefundStatusEnum.WAIT_RECEIVE.getStatus() == orderRefund.getRefundStatus());
        }
        return false;
    }

    /**
     * 获取订单子项售后状态
     */
    @Override
    public String getOrderItemRefundStatusName(Long orderId, Long orderItemId) {
        List<OrderRefundDto> list = this.listWithoutInvalidByOrderId(orderId);
        if(CollectionUtil.isNotEmpty(list)) {
            if(list.size() == 1 && null == list.get(0).getOrderItemId()) {
                return RefundStatusEnum.getNameByStatus(list.get(0).getRefundStatus());
            }else {
                List<OrderRefundDto> orderItemRefundList = list.stream().filter(orderRefundDto -> orderItemId.compareTo(orderRefundDto.getOrderItemId()) == 0).collect(Collectors.toList());
                if(CollectionUtil.isNotEmpty(orderItemRefundList)) {
                    return RefundStatusEnum.getNameByStatus(orderItemRefundList.get(0).getRefundStatus());
                }
            }
        }
        return "";
    }

    /**
     * 售后列表
     */
    @Override
    public OrderRefundDtoForAdmin listForAdmin(Long orderId) {
        OrderRefundDtoForAdmin result = new OrderRefundDtoForAdmin();
        List<OrderRefundHistory> orderRefundHistoryList = orderRefundHistoryService.list(new QueryWrapper<OrderRefundHistory>().eq("order_id", orderId));

        List<OrderRefundDto> currentList = this.listByOrderId(orderId);
        List<OrderRefundDto> historyList = ConvertUtils.OrderRefundModule.INSTANCE.historyListToDtoList(orderRefundHistoryList);

        Iterator<OrderRefundDto> iterator = currentList.iterator();
        while (iterator.hasNext()) {
            OrderRefundDto orderRefund = iterator.next();
            Integer refundStatus = orderRefund.getRefundStatus();
            if(RefundStatusEnum.REFUSE.getStatus() == refundStatus
                || RefundStatusEnum.RECEIVED.getStatus() == refundStatus
                || RefundStatusEnum.FINISH_REFUND.getStatus() == refundStatus
                || RefundStatusEnum.CANCELED.getStatus() == refundStatus
                || (RefundStatusEnum.APPROVE.getStatus() == refundStatus && RefundTypeEnum.RETURN.getType() == orderRefund.getRefundType())) {
                historyList.add(orderRefund);
                iterator.remove();
            }
        }

        result.setHistoryList(historyList);
        result.setCurrentList(currentList);
        return result;
    }

    /**
     * 售前申请退款
     */
    @Transactional
    @Override
    public void applyRefund(OrderApplyRefundRequest request) {
        OrderDto order = orderService.info(request.getOrderId());
        XmallUtils.notNull(order);

        // 检查售后状态
        if(AfterSaleStatusEnum.UN_VALID.getStatus() == order.getAfterSaleStatus()) {
            throw new XmallException(ResultCode.ORDER_REFUND_REPEAT_ERROR);
        }

        // 已拒绝记录存入历史表
        orderRefundHistoryService.moveToHistory(request.getOrderId(), null);

        // 保存申请信息
        OrderRefund entity = new OrderRefund();
        entity.setOrderId(request.getOrderId());
        entity.setRefundStatus(RefundStatusEnum.WAIT_AUDIT.getStatus());
        entity.setRefundType(RefundTypeEnum.ONLY_REFUND.getType());
        entity.setPayAmount(order.getPayAmount());
        entity.setRefundAmount(order.getPayAmount());
        entity.setApplyReason(request.getReason());
        this.save(entity);

        // 设置订单售后状态
        orderService.setOrderAfterSaleStatus(request.getOrderId(), AfterSaleStatusEnum.UN_VALID);
        orderService.setOrderItemAfterSaleStatusByOrderId(request.getOrderId(), AfterSaleStatusEnum.UN_VALID);

        // 订单状态（必须为待发货）
        orderService.updateOrderStatusStrict(request.getOrderId(), OrderStatusEnum.WAIT_CONSIGN, OrderStatusEnum.WAIT_CONSIGN);
    }

    /**
     * 售后申请退款
     */
    @Transactional
    @Override
    public void applyReturn(OrderApplyReturnRequest request) {
        OrderDtoWithCascade order = orderService.infoWithCascade(request.getOrderId());
        XmallUtils.notNull(order);

        boolean isAllReturn = order.getOrderItems().stream().allMatch(orderItemDto -> request.getOrderItemIds().contains(orderItemDto.getId()));
        if(isAllReturn) {
            // 检查售后状态
            if(AfterSaleStatusEnum.UN_VALID.getStatus() == order.getAfterSaleStatus()) {
                throw new XmallException(ResultCode.ORDER_REFUND_REPEAT_ERROR);
            }

            // 已拒绝记录存入历史表
            orderRefundHistoryService.moveToHistory(request.getOrderId(), null);

            // 设置订单售后状态
            orderService.setOrderAfterSaleStatus(request.getOrderId(), AfterSaleStatusEnum.UN_VALID);
            orderService.setOrderItemAfterSaleStatusByOrderId(request.getOrderId(), AfterSaleStatusEnum.UN_VALID);

            // 保存记录
            OrderRefund entity = new OrderRefund();
            entity.setOrderId(request.getOrderId());
            entity.setRefundStatus(RefundStatusEnum.WAIT_AUDIT.getStatus());
            entity.setRefundType(request.getRefundType());
            entity.setPayAmount(order.getPayAmount());
            entity.setRefundAmount(order.getPayAmount());
            entity.setApplyReason(request.getReason());
            this.save(entity);
        }

        // 部分退款
        if(!isAllReturn) {
            List<OrderRefund> orderRefundList = request.getOrderItemIds().stream().map(orderItemId -> {
                OrderItem orderItem = orderItemService.getById(orderItemId);
                XmallUtils.notNull(orderItem);

                // 检查售后状态
                if(AfterSaleStatusEnum.UN_VALID.getStatus() == orderItem.getAfterSaleStatus()) {
                    throw new XmallException(ResultCode.ORDER_REFUND_REPEAT_ERROR);
                }

                // 已拒绝记录存入历史表
                orderRefundHistoryService.moveToHistory(request.getOrderId(), orderItemId);

                // 设置订单售后状态
                orderService.setOrderAfterSaleStatus(request.getOrderId(), AfterSaleStatusEnum.UN_VALID);
                orderService.setOrderItemAfterSaleStatus(orderItemId, AfterSaleStatusEnum.UN_VALID);

                // 保存记录
                OrderRefund entity = new OrderRefund();
                entity.setOrderId(request.getOrderId());
                entity.setOrderItemId(orderItemId);
                entity.setRefundStatus(RefundStatusEnum.WAIT_AUDIT.getStatus());
                entity.setRefundType(request.getRefundType());
                entity.setPayAmount(orderItem.getTotalAmount());
                entity.setRefundAmount(orderItem.getTotalAmount());
                entity.setApplyReason(request.getReason());
                return entity;
            }).collect(Collectors.toList());
            this.saveBatch(orderRefundList);
        }
    }

    /**
     * 售前申请退款：同意
     */
    @Transactional
    @Override
    public void approveRefund(Long id) {
        OrderRefund orderRefund = this.getById(id);
        XmallUtils.notNull(orderRefund);

        this.updateToApproveStatus(orderRefund.getId());

        // 设置售后状态
        orderService.setOrderAfterSaleStatus(orderRefund.getOrderId(), AfterSaleStatusEnum.UN_VALID);
        orderService.setOrderItemAfterSaleStatusByOrderId(orderRefund.getOrderId(), AfterSaleStatusEnum.UN_VALID);

        // 保存日志，修改订单状态，并发送退款消息
        Long logId = orderRefundRetryLogService.save(orderRefund.getId(), orderRefund.getRefundAmount());
        orderService.updateOrderStatus(orderRefund.getOrderId(), OrderStatusEnum.REFUNDING);
        msgService.sendOrderRefundMsg(logId);
    }

    /**
     * 售后退款：同意
     */
    @Transactional
    @Override
    public void approveReturn(Long id) {
        OrderRefund orderRefund = this.getById(id);
        XmallUtils.notNull(orderRefund);

        this.updateToApproveStatus(orderRefund.getId());

        // 仅退款
        if(RefundTypeEnum.ONLY_REFUND.getType() == orderRefund.getRefundType()) {
            // 保存日志，修改订单状态，并发送退款消息
            Long logId = orderRefundRetryLogService.save(orderRefund.getId(), orderRefund.getRefundAmount());
            orderService.updateOrderStatus(orderRefund.getOrderId(), OrderStatusEnum.REFUNDING);
            msgService.sendOrderRefundMsg(logId);
        }

        // 设置订单售后状态
        if(null == orderRefund.getOrderItemId()) {
            orderService.setOrderAfterSaleStatus(orderRefund.getOrderId(), AfterSaleStatusEnum.UN_VALID);
            orderService.setOrderItemAfterSaleStatusByOrderId(orderRefund.getOrderId(), AfterSaleStatusEnum.UN_VALID);
        }else {
            orderService.setOrderAfterSaleStatus(orderRefund.getOrderId(), AfterSaleStatusEnum.UN_VALID);
            orderService.setOrderItemAfterSaleStatus(orderRefund.getOrderItemId(), AfterSaleStatusEnum.UN_VALID);
        }
    }

    /**
     * 售前退款：拒绝
     */
    @Transactional
    @Override
    public void refuseRefund(OrderRefuseRefundRequest request) {
        OrderRefund entity = this.getById(request.getId());
        XmallUtils.notNull(entity);

        this.updateToRefuseStatus(request.getId(), request.getReason());

        // 设置订单售后状态
        orderService.setOrderAfterSaleStatus(entity.getOrderId(), AfterSaleStatusEnum.VALID);
        orderService.setOrderItemAfterSaleStatusByOrderId(entity.getOrderId(), AfterSaleStatusEnum.UN_VALID);
    }

    /**
     * 售后退款：拒绝
     */
    @Transactional
    @Override
    public void refuseReturn(OrderRefuseReturnRequest request) {
        OrderRefund entity = this.getById(request.getId());
        XmallUtils.notNull(entity);

        this.updateToRefuseStatus(request.getId(), request.getReason());

        // 设置订单售后状态
        if(null == entity.getOrderItemId()) {
            orderService.setOrderAfterSaleStatus(entity.getOrderId(), AfterSaleStatusEnum.VALID);
            orderService.setOrderItemAfterSaleStatusByOrderId(entity.getOrderId(), AfterSaleStatusEnum.VALID);
        }else {
            if(CollectionUtil.isEmpty(this.listWithoutInvalidByOrderId(entity.getOrderId()))) {
                orderService.setOrderAfterSaleStatus(entity.getOrderId(), AfterSaleStatusEnum.VALID);
            }else {
                orderService.setOrderAfterSaleStatus(entity.getOrderId(), AfterSaleStatusEnum.UN_VALID);
            }
            orderService.setOrderItemAfterSaleStatus(entity.getOrderItemId(), AfterSaleStatusEnum.VALID);
        }
    }

    /**
     * 退货发货
     */
    @Override
    public void returnDelivery(OrderReturnDeliveryRequest request) {
        OrderRefund orderRefund = this.getOne(new QueryWrapper<OrderRefund>()
            .eq("order_id", request.getOrderId())
            .isNull(null == request.getOrderItemId(), "order_item_id")
            .eq(null != request.getOrderItemId(), "order_item_id", request.getOrderItemId()));
        XmallUtils.notNull(orderRefund);

        OrderRefund updateOrderRefund = new OrderRefund();
        updateOrderRefund.setRefundStatus(RefundStatusEnum.WAIT_RECEIVE.getStatus());
        updateOrderRefund.setDeliveryTime(new Date());
        boolean executeResult = this.update(updateOrderRefund, new QueryWrapper<OrderRefund>().eq("id", orderRefund.getId())
            .eq("refund_status", RefundStatusEnum.APPROVE.getStatus())
            .eq("refund_type", RefundTypeEnum.RETURN.getType()));
        if(!executeResult) {
            throw new XmallException(ResultCode.ORDER_REFUND_STATUS_ERROR);
        }
    }

    /**
     * 退货收货
     */
    @Transactional
    @Override
    public void returnDeliveryReceive(Long id) {
        OrderRefund orderRefund = this.getById(id);
        XmallUtils.notNull(orderRefund);

        OrderRefund updateOrderRefund = new OrderRefund();
        updateOrderRefund.setRefundStatus(RefundStatusEnum.RECEIVED.getStatus());
        updateOrderRefund.setFinishTime(new Date());
        boolean executeResult = this.update(updateOrderRefund, new QueryWrapper<OrderRefund>().eq("id", id)
                .eq("refund_status", RefundStatusEnum.WAIT_RECEIVE.getStatus()));
        if(!executeResult) {
            throw new XmallException(ResultCode.ORDER_REFUND_STATUS_ERROR);
        }

        // 保存日志，修改订单状态，并发送退款消息
        Long logId = orderRefundRetryLogService.save(orderRefund.getId(), orderRefund.getRefundAmount());
        orderService.updateOrderStatus(orderRefund.getOrderId(), OrderStatusEnum.REFUNDING);
        msgService.sendOrderRefundMsg(logId);
    }

    /**
     * 同意
     */
    private void updateToApproveStatus(Long id) {
        OrderRefund entity = this.getById(id);
        XmallUtils.notNull(entity);

        OrderRefund updateEntity = new OrderRefund();
        updateEntity.setRefundStatus(RefundStatusEnum.APPROVE.getStatus());
        updateEntity.setAuditTime(new Date());
        boolean executeResult = this.update(updateEntity, new QueryWrapper<OrderRefund>().eq("id", id).eq("refund_status", RefundStatusEnum.WAIT_AUDIT.getStatus()));
        if(!executeResult) {
            throw new XmallException(ResultCode.ORDER_REFUND_STATUS_ERROR);
        }
    }

    /**
     * 拒绝
     */
    private void updateToRefuseStatus(Long id, String reason) {
        OrderRefund entity = this.getById(id);
        XmallUtils.notNull(entity);

        OrderRefund updateEntity = new OrderRefund();
        updateEntity.setRefundStatus(RefundStatusEnum.REFUSE.getStatus());
        updateEntity.setAuditTime(new Date());
        updateEntity.setRefuseReason(reason);
        boolean executeResult = this.update(updateEntity, new QueryWrapper<OrderRefund>().eq("id", id).eq("refund_status", RefundStatusEnum.WAIT_AUDIT.getStatus()));
        if(!executeResult) {
            throw new XmallException(ResultCode.ORDER_REFUND_STATUS_ERROR);
        }
    }

}
